//consumer productor

#include "BlockQueue.hpp"
#include "Task.hpp"
#include <sys/types.h>
#include <unistd.h>
#include <ctime>

const std::string oper = "+-*/%";
//C:计算
//S:存储
template <class C, class S>
class BlockQueues
{
public:
    BlockQueue<C> *c_bq;
    BlockQueue<S> *s_bq;
};

void *produce(void *para_bq)
{
    // BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(para_bq);
    BlockQueue<CalTask> *bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(para_bq))->c_bq;

    while(true)
    {
        //produce activity...
        // int data = rand() % 10 + 1;//在这里我们先用随机数，构建出一个数据
        //从数据库，网络，外设，拿来的用户数据！
        int x = rand() % 10 + 1;
        int y = rand() % 5;//第二个操作数可能为0
        int operCode = rand() % oper.size();
        
        CalTask t(x, y, oper[operCode], mymath);
        bq->push(t);
        // std::cout << "生产数据: " << data << std::endl;
        std::cout << "生产任务: " << t.toTaskString() << std::endl;
        sleep(1);
    }

    return nullptr;
}
void *consume(void *para_bq)//parameters
{
    // BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(para_bq);
    BlockQueue<CalTask> *bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(para_bq))->c_bq;
    BlockQueue<SaveTask> *save_bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(para_bq))->s_bq;
    // int cnt = 2;
    while(true)
    {
        //consume activity...
        // int data;
        CalTask t;
        bq->pop(&t);
        //有没有可能执行的任务非常耗时间？
        std::string result = t();
        std::cout << "consume thread: 计算任务: " << result << " ...done " << std::endl;

        SaveTask save(result, Save);
        save_bq->push(save);
        std::cout << "consume thread: 推送->保存任务 完成..." << std::endl;

        // sleep(1);
    }

    return nullptr;
}

void *save(void *para_bq)
{
    BlockQueue<SaveTask> *save_bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(para_bq))->s_bq;

    while(true)
    {
        SaveTask t;
        save_bq->pop(&t);
        t();//执行SaveTask的仿函数
        std::cout << "保存任务->文件 完成..." << std::endl;
    }

    return nullptr;
}

int main()
{
    // 由于 rand() 函数生成的是伪随机数，因此它不是真正的随机数，而是通过算法计算得出的数值序列。每次程序运行时，如果使用相同的种子值初始化随机数生成器，
    // 那么生成的随机数序列也会相同。因此，在生成随机数时，我们通常会使用当前时间作为种子值，以尽量保证生成的随机数序列的多样性。
    srand(time(nullptr) ^ getpid() ^ 0x12348765);//让随机数种子更为随机一些

    BlockQueues<CalTask, SaveTask> bqs;

    // BlockQueue<int> bq;//线程能看到的同一份阻塞队列
    // BlockQueue<int> *bq = new BlockQueue<int>();//开辟在堆上好一点
    bqs.c_bq= new BlockQueue<CalTask>;//开辟在堆上好一点
    bqs.s_bq= new BlockQueue<SaveTask>;

    pthread_t c[2], p[3];//生产还是消费之前，得让c和p看到同一个交易场所，也就是同一个阻塞队列
    pthread_create(c, nullptr, consume, &bqs);//传bq就可以让多个线程看到同一份阻塞队列了
    pthread_create(c+1, nullptr, consume, &bqs);
    pthread_create(p, nullptr, produce, &bqs);
    pthread_create(p+1, nullptr, produce, &bqs);
    pthread_create(p+2, nullptr, produce, &bqs);


    // bqs.s_bq= new BlockQueue<SaveTask>;//在这里定义，有可能上面的consume线程放save内容时，第二个阻塞队列没开辟好，指针是野指针


    pthread_t s;
    pthread_create(&s, nullptr, save, &bqs);

    pthread_join(c[0], nullptr);
    pthread_join(c[1], nullptr);
    pthread_join(p[0], nullptr);
    pthread_join(p[1], nullptr);
    pthread_join(p[2], nullptr);
    pthread_join(s, nullptr);

    delete bqs.c_bq;
    delete bqs.s_bq;

    return 0;
}